#!/bin/bash

SCRIPT_NAME=$(basename $0)
N_SLAVES=0
BOND_NAME="bond0"
MIIMON=100
loud=0
VERSION=0.9.0
RELEASE=12
IPOIB_MTU=65520
mode=
print(){
	if [ $loud -ne 0 ] ; then
		echo $*
	fi
}

usage(){
        echo "Usage: $SCRIPT_NAME --bond-name <bond?> --bond-ip <ip[/mask]> --slaves <ib?[,ib?,ib?...]> --miimon <val>  --stop[-all] --status[-all] -v --version"
	echo "	bond name defaults to \"bond0\"."
	echo "	slaves default to ib0,ib1."
}

print_bond(){
	local i=0
	if [ ! -f /proc/net/bonding/$BOND_NAME ] ; then
		return
	fi
	ip_addr=$(ip addr show dev $BOND_NAME|grep -w inet|tr -s " "|cut -f3 -d" ")
	addr=$(cat /sys/class/net/$BOND_NAME/address)
	print $BOND_NAME: $addr $ip_addr
	active=$(cat /sys/class/net/$BOND_NAME/bonding/active_slave)
	for slave in $(cat /sys/class/net/$BOND_NAME/bonding/slaves) ; do
		is_up=$(ip addr show dev $slave up |wc -l)
		if [ $is_up -ne 0 ] ; then
			print -en slave$i: $slave
		else
			print -en slave$i: '\E[31;50m'$slave
		fi
		if [ ! -z $active ] ; then
			if [ $slave = $active ] ; then
				print -e '\033[1m' "\052"
			else
				print 
			fi
		else
			print
		fi
		tput sgr0
		i=$((i+1))
	done
}

print_all_bonds(){
	if [ ! -d /proc/net/bonding/ ] ; then
		return
	fi
	all_bonds=$(ls /proc/net/bonding/)
	for bond in $all_bonds ; do
		BOND_NAME=$bond
		print_bond
	done
}

stop_bond(){
	if [ ! -f /proc/net/bonding/$BOND_NAME ] ; then
		print bonding is not up
		return
	fi
	bond_mtu=$(cat /sys/class/net/$BOND_NAME/mtu)
	for slave in $(cat /proc/net/bonding/$BOND_NAME |grep ^Slave|cut -f2 -d:) ; do
		echo -$slave > /sys/class/net/$BOND_NAME/bonding/slaves
		ifconfig $slave mtu $bond_mtu
		print unenslave $slave
	done
	
	echo -$BOND_NAME > /sys/class/net/bonding_masters
	print "${BOND_NAME} removed"
	
 	if [ -z "$(cat  /sys/class/net/bonding_masters)" ]; then
		modprobe -r bonding
		print bonding module unloaded
	fi
}

stop_all_bonds(){
	if [ ! -d /proc/net/bonding/ ] ; then
		return
	fi
	all_bonds=$(ls /proc/net/bonding/)
	for bond in $all_bonds ; do
		BOND_NAME=$bond
		stop_bond
	done
}

create_slaves(){
	local i=0
	while [ $i -lt $N_SLAVES ] ; do
		slave=$(echo ${SLAVE[$i]})
		IF_NAME=$(echo $slave |cut -d '.' -f 1 )
		IF_PKEY=$(echo $slave |cut -d '.' -f 2 -s)
		if [ -z ${IF_PKEY} ]; then
			ifconfig ${IF_NAME} down
			i=$((i+1))
   			continue
		fi
		if [ -e /sys/class/net/${IF_NAME}/create_child ]; then
			if [ ! -e /sys/class/net/${IF_NAME}.${IF_PKEY} ]; then
				print Creating $IF_NAME.$IF_PKEY
				echo 0x$IF_PKEY > /sys/class/net/${IF_NAME}/create_child
			else
				print "${IF_NAME}.${IF_PKEY} exists. Running \"ifconfig ${IF_NAME}.${IF_PKEY} down\"."
				ifconfig ${IF_NAME}.${IF_PKEY} down
			fi
		fi
		i=$((i+1))
	done
}

enslave_all(){
	local i=0
	while [ $i -lt $N_SLAVES ] ; do
		slave=$(echo ${SLAVE[$i]})
		print enslaving $slave
		echo +$slave > /sys/class/net/$BOND_NAME/bonding/slaves	
		i=$((i+1))
	done
}
	
check_slaves_mtu(){
	local i=0
        while [ $i -lt $N_SLAVES ] ; do
			slave=$(echo ${SLAVE[$i]})
			if [ -e /sys/class/net/$slave/mtu ] ; then
				if [ $(cat /sys/class/net/$slave/mtu) -lt $IPOIB_MTU ] ; then
					IPOIB_MTU=$(cat /sys/class/net/$slave/mtu)
				fi
			else
				IPOIB_MTU=1500
			fi
			i=$((i+1))
        done
}

parse_bond_name(){
	BOND_NAME=$(echo $1)
	if [ -z $BOND_NAME ] ; then
		usage
		exit 1
	fi
}

parse_bond_ip(){
	BOND_IP=$(echo $1|cut -f1 -d/)
	if [ -z $BOND_IP ] ; then
		usage
		exit 1
	fi
	BOND_NETMASK=$(echo $1|cut -s -f2 -d/)
}
parse_slave_string(){
	SLAVE[$N_SLAVES]=$(echo $1|cut -f1 -d,)
	if [ -z ${SLAVE[$N_SLAVES]} ] ; then
		usage
		exit 1
	fi
	while [ ! -z "${SLAVE[$N_SLAVES]}" ] ; do
		N_SLAVES=$((N_SLAVES+1))
		SLAVE[$N_SLAVES]=$(echo $1|cut -s -f$(($N_SLAVES+1)) -d,)
	done
}
while [[ ! -z "$1" ]] ; do
        case $1 in
			--bond-name)
			parse_bond_name $2
			shift
			shift
		;;
			--bond-ip)
			parse_bond_ip $2
                        shift
                        shift
		;;
			--slaves)
			parse_slave_string $2
                        shift
                        shift
                ;;
			--miimon)
			MIIMON=$2
			shift
			shift
		;;
			-v)
			loud=1
			shift
		;;
			--version)
			echo ib-bonding-$VERSION-$RELEASE
			exit 0
		;;
			--stop)
			stop_bond
			exit 0
			shift
		;;
			--stop-all)
			stop_all_bonds
			exit 0
			shift
		;;
			--status)
			loud=1
			print_bond
			exit 0
			shift
		;;
			--status-all)
			loud=1
			print_all_bonds
			exit 0
			shift
		;;
			*)
			usage
			exit 1
                ;;
        esac
done


if [ -z $BOND_IP ] ; then
	usage
	exit 1
fi
if [ -z $BOND_NETMASK ] ; then
	BOND_NETMASK=24
fi

if [ $N_SLAVES -eq 0 ] ; then
	N_SLAVES=2
	SLAVE[0]=ib0
	SLAVE[1]=ib1
fi


if ( ! lsmod|grep ^bonding &>/dev/null); then
	modprobe bonding
fi

if [ ! -f /proc/net/bonding/$BOND_NAME ] ; then
	echo +${BOND_NAME} > /sys/class/net/bonding_masters 
else
	if [ ! -z "$(cat /sys/class/net/$BOND_NAME/bonding/slaves)" ] ; then
		echo Error: $BOND_NAME already exists and has slaves.
		exit 1
	fi
fi

if [ ! -f /proc/net/bonding/$BOND_NAME ] ; then
	echo "Error: can't create $BOND_NAME device."
	exit 1
fi

echo active-backup > /sys/class/net/$BOND_NAME/bonding/mode
echo $MIIMON       > /sys/class/net/$BOND_NAME/bonding/miimon
create_slaves
check_slaves_mtu
enslave_all

ifconfig $BOND_NAME up mtu $IPOIB_MTU
ip addr  add dev $BOND_NAME $BOND_IP/$BOND_NETMASK brd +

print bonding is up: $BOND_IP
print_bond
exit 0
